package borderPatrol.misc;

import java.io.Serializable;
import java.util.LinkedList;

import borderPatrol.Data.Move;

public class CFRInformationSet implements Serializable {

	private static final long serialVersionUID = 1L;

	private LinkedList<Move> moves;
	private LinkedList<History> possibleHistories;
	private LinkedList<Integer> poachersWinningCoordinates;

	private float[] values;
	private float[] strategy;
	private float[] regret;
	private float[] numerator;
	private float[] averageStrategy;

	private float probabilityOfOccurence;
	private float probabilitySum;
	private int isTerminal;
	private int historySize;

	@SuppressWarnings("unchecked")
	public CFRInformationSet(LinkedList<Move> moves, int isTerminal, LinkedList<History> possibleHistories) {
		
		this.possibleHistories = Cloner.cloneHistories(possibleHistories);
		this.historySize = -1;
		this.probabilitySum = 0;

		if (moves != null)
			this.moves = (LinkedList<Move>) moves.clone();

		this.isTerminal = isTerminal;

		if (moves != null) {
			values = new float[moves.size()];
			strategy = new float[moves.size()];
			regret = new float[moves.size()];
			numerator = new float[moves.size()];
			averageStrategy = new float[moves.size()];

			probabilityOfOccurence = 1;

			for (int i = 0; i < strategy.length; i++) {
				strategy[i] = (float) 1 / moves.size();
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	public CFRInformationSet(LinkedList<Move> moves, int isTerminal, LinkedList<Integer> poachersWinningCoordinates, int historySize) {
		
		this.historySize = historySize;
		this.poachersWinningCoordinates = (LinkedList<Integer>) poachersWinningCoordinates.clone();

		if (moves != null)
			this.moves = (LinkedList<Move>) moves.clone();

		this.isTerminal = isTerminal;

		if (moves != null) {
			values = new float[moves.size()];
			strategy = new float[moves.size()];
			regret = new float[moves.size()];

			probabilityOfOccurence = 1;

			for (int i = 0; i < strategy.length; i++) {
				strategy[i] = (float) 1 / moves.size();
			}
		}
	}

	public LinkedList<Move> getMoves() {
		return moves;
	}

	public int getIsTerminal() {
		return isTerminal;
	}

	public float[] getRegret() {
		return regret;
	}

	public float[] getStrategy() {
		return strategy;
	}

	public float[] getValues() {
		return values;
	}
	
	public void setProbabilityOfOccurence(float probabilityOfOccurence) {
		this.probabilityOfOccurence = probabilityOfOccurence;
	}
	
	public float getProbabilityOfOccurence() {
		return probabilityOfOccurence;
	}
	
	public int getHistorySize() {
		return historySize == -1?possibleHistories.size():historySize;
	}
	
	public LinkedList<History> getPossibleHistories() {
		return possibleHistories;
	}
	
	public LinkedList<Integer> getPoachersWinningCoordinates() {
		return poachersWinningCoordinates;
	}
	
	public void setValues(float[] values) {
		this.values = values.clone();
	}

	public void addProbabilityToSum() {
		probabilitySum += probabilityOfOccurence;		
	}
	
	private void addStrategyToNumeragtors() {
		for (int i = 0; i < strategy.length; i++) {
			numerator[i] += probabilityOfOccurence*strategy[i];
		}
	}
	
	public void computeAverageStrategy() {
		
		addStrategyToNumeragtors();
		
		for (int i = 0; i < averageStrategy.length; i++) {
			averageStrategy[i] = numerator[i]/probabilitySum;
		}
	}
	
	public float[] getAverageStrategy() {
		return averageStrategy;
	}
	
	public String toString() {

		String regretString = "regret: [";
		String valuesString = "values: [";
		String strategyString = "strategy: [";
		String averageStrategyString = "average strategy: [";
		String movesString = "";
		String eol = System.getProperty("line.separator");

		movesString = "[" + moves + "]";

		for (int i = 0; i < regret.length; i++) {
			if (regret != null)
				regretString = regretString + regret[i] + ", ";
			if (values != null)
				valuesString = valuesString + values[i] + ", ";
			if (strategy != null)
				strategyString = strategyString + strategy[i] + ", ";
			if (averageStrategy != null)
				averageStrategyString = averageStrategyString + averageStrategy[i] + ", ";
		}

		regretString = regretString + "]";
		valuesString = valuesString + "]";
		strategyString = strategyString + "]";
		averageStrategyString = averageStrategyString + "]";

		return "{" + movesString + ", " + eol + regretString + ", " + eol + valuesString + ", " + eol + strategyString  + ", " + eol + averageStrategyString + ", " + eol + probabilityOfOccurence + eol + possibleHistories + "}";
	
	}
}
